//
//  SocketRocketUtility.m
//  SUN
//
//  Created by 孙俊 on 17/2/16.
//  Copyright © 2017年 SUN. All rights reserved.
//

#import "SocketRocketUtility.h"



#define dispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}

@interface SocketRocketUtility()<SRWebSocketDelegate>
{
    int _index;
    NSTimer * heartBeat;
    NSTimeInterval reConnectTime;
    
}

@property (nonatomic,strong) SRWebSocket *socket;
@property(nonatomic,strong)NSMutableArray *notifyAry;
@property(nonatomic,strong)NSString *currentNotifyID;

@end

@implementation SocketRocketUtility

+(SocketRocketUtility *)instance{
    static SocketRocketUtility *Instance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        Instance = [[SocketRocketUtility alloc] init];
       
    });
    return Instance;
}

-(NSString*)genServerAddressWithToken:(NSString*)token userId:(NSString*)userid{
    NSString *url=nil;
    if([[YiChatClient shareInstance].host hasPrefix:@"https"])
    {
        url=[NSString stringWithFormat:@"wss://%@:%d/yichat/broker/websocket?token=%@&platform=IOS&version=2&userId=%@",_serverHost, _wssPort,token,userid];
    }
    else if([[YiChatClient shareInstance].host hasPrefix:@"http"])
    {
         url=[NSString stringWithFormat:@"ws://%@:%d/yichat/broker/websocket?token=%@&platform=IOS&version=2&userId=%@",_serverHost, _wsPort,token,userid];
    }
    
    _serverAddress = url;
    return url;
}

//-(void)SRWebSocketOpen
-(void)SRWebSocketOpenwithServer:(NSString*)server token:(NSString*)token userId:(NSString*)userid
{
    
    //如果是同一个url return
    if (self.socket) {
        return;
    }
    
    self.token = token;
    self.userId = userid;
    
    NSString* url = [self genServerAddressWithToken:token userId:userid];
    NSLog(@"SRWebSocketOpenwithServer userid:%@", userid);
    NSLog(@"xxxx  websocket url:%@", url);
    
    //self.socket = [[SRWebSocket alloc] initWithURLRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:url]]];//这里填写你服务器的地址
    self.socket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] protocols:nil allowsUntrustedSSLCertificates:NO];
//    NSLog(@"请求的websocket地址：%@",self.socket.url.absoluteString);
    //20190111修改
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(SRWebSocketDidOpen) name:@"kWebSocketDidOpenNote" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(SRWebSocketDidReceiveMsg:) name:@"kWebSocketdidReceiveMessageNote" object:nil];

    self.socket.delegate = self;   //实现这个 SRWebSocketDelegate 协议
    
    [self.socket open];     //open 就是直接连接了
}


-(void)SRWebSocketClose{
    if (self.socket){
        [self.socket close];
        self.socket = nil;
        //断开连接时销毁心跳
        [self destoryHeartBeat];
        NSLog(@"socket销毁了");
    }
}

#pragma mark - socket delegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    
    //每次正常连接的时候清零重连时间
    reConnectTime = 0;
    
    //开启心跳
    [self initHeartBeat];
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket 连接成功************************** ");
        [[NSNotificationCenter defaultCenter] postNotificationName:@"kWebSocketDidOpenNote" object:nil];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {

    if (webSocket == self.socket) {
        NSLog(@"************************** socket 连接失败************************** :%@", error);
        _socket = nil;
        //连接失败就重连
        [self reConnect];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket连接断开************************** ");
        NSLog(@"被关闭连接，code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);

//            [self SRWebSocketClose];
             [self reConnect];
    }

}

/*该函数是接收服务器发送的pong消息，其中最后一个是接受pong消息的，
 在这里就要提一下心跳包，一般情况下建立长连接都会建立一个心跳包，
 用于每隔一段时间通知一次服务端，客户端还是在线，这个心跳包其实就是一个ping消息，
 我的理解就是建立一个定时器，每隔十秒或者十五秒向服务端发送一个ping消息，这个消息可是是空的
 */

-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
    NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
    NSLog(@"reply===%@",reply);
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
    
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket收到数据了************************** ");
//        NSLog(@"我这后台约定的 message 是 json 格式数据收到数据，就按格式解析吧，然后把数据发给调用层");
        NSLog(@"message:%@",message);

        [[NSNotificationCenter defaultCenter] postNotificationName:@"kWebSocketdidReceiveMessageNote" object:message];
    }
}

//重连机制
- (void) reConnect
{
    [self SRWebSocketClose];
    NSLog(@"time %f",reConnectTime);
    //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        //        [self SRWebSocketOpen];
        
        //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
        if (reConnectTime > 300) {
            //您的网络状况不是很好，请检查网络后重试
            reConnectTime = 0;
            return;
        }
        
        reConnectTime += 3;
        //        [self SRWebSocketOpen];
        
        self.socket = nil;
        NSString* url = _serverAddress;
        [self SRWebSocketOpenwithServer:url token:[SocketRocketUtility instance].token userId:self.userId];
        NSLog(@"重连");
    });
    
    //重连时间2的指数级增长
    //    if (reConnectTime == 0) {
    //        reConnectTime = 2;
    //    }else{
    //        reConnectTime *= 2;
    //    }
    
}

//初始化心跳
- (void)initHeartBeat
{
    dispatch_main_async_safe(^{
        [self destoryHeartBeat];
        //心跳设置为3分钟，NAT超时一般为5分钟
        heartBeat = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];
        //和服务端约定好发送什么作为心跳标识，尽可能的减小心跳包大小
        [[NSRunLoop currentRunLoop]addTimer:heartBeat forMode:NSRunLoopCommonModes];
    })
}

-(void)sentheart{
    //发送心跳 和后台可以约定发送什么内容
//    [self sendData:@"heart"];
}

//取消心跳
- (void)destoryHeartBeat
{
    dispatch_main_async_safe(^{
        if (heartBeat) {
            if ([heartBeat respondsToSelector:@selector(isValid)]){
                if ([heartBeat isValid]){
                    [heartBeat invalidate];
                    heartBeat = nil;
                }
            }
        }
    })
}


//pingPong
- (void)ping{
    if (self.socket.readyState == SR_OPEN) {
        //[self.socket sendPing:nil];
        
    }
}

#define WeakSelf(ws) __weak __typeof(&*self)weakSelf = self
- (void)sendData:(id)data {
    NSLog(@"socketSendData --------------- %@",data);
    
    WeakSelf(ws);
    dispatch_queue_t queue =  dispatch_queue_create("zy", NULL);
    
    dispatch_async(queue, ^{
        if (weakSelf.socket != nil) {
            // 只有 SR_OPEN 开启状态才能调 send 方法啊，不然要崩
            if (weakSelf.socket.readyState == SR_OPEN) {
//                NSLog(@"发送数据前");
                [weakSelf.socket send:data];    // 发送数据
//                NSLog(@"发送数据后");
                
            } else if (weakSelf.socket.readyState == SR_CONNECTING) {
                NSLog(@"正在连接中，重连后其他方法会去自动同步数据");
                // 每隔2秒检测一次 socket.readyState 状态，检测 10 次左右
                // 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
                // 如果 10 次都还是没连上的，那这个发送请求就丢失了，这种情况是服务器的问题了，小概率的
                // 代码有点长，我就写个逻辑在这里好了
                [self reConnect];
                
            } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
                // websocket 断开了，调用 reConnect 方法重连
                
//                NSLog(@"重连");
                
                [self reConnect];
            }
        } else {
             NSLog(@"没网络，发送失败.");
//            NSLog(@"没网络，发送失败，一旦断网 socket 会被我设置 nil 的");
//            NSLog(@"其实最好是发送前判断一下网络状态比较好，我写的有点晦涩，socket==nil来表示断网");
        }
    });
}

-(SRReadyState)socketReadyState{
    return self.socket.readyState;
}


-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)SRWebSocketDidOpen {
    NSLog(@"开启成功");
    //在成功后需要做的操作。。。
    
    
}

- (void)SRWebSocketDidReceiveMsg:(NSNotification *)note {
    //收到服务端发送过来的消息
    NSString * messageStr = note.object;
    NSData *data=[messageStr dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *message=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
    
    NSString* content = message[@"resultData"][@"content"];
    NSLog(@"SDK收到来自服务端的消息:%@",message);
    NSLog(@"SDK收到来自服务端的消息 content:%@",content);
    
    if(message[@"response"][@"notifyId"])
    {
        NSString *notifyId=[NSString stringWithFormat:@"%@",message[@"response"][@"notifyId"]];
        NSString *timestamp=[NSString stringWithFormat:@"%@",message[@"response"][@"timestamp"]];
        self.currentNotifyID=notifyId;
        NSDictionary *oneNotifyDic=@{notifyId:timestamp};
        
        [self.notifyAry addObject:oneNotifyDic];
        BOOL isHaveNotifyId=[self findNotifyId:self.currentNotifyID InAry:[self.notifyAry copy]];
        if(isHaveNotifyId==YES) //消息数组中已经有这个notifyId
        {
            NSString *receiptStr=[self getRecipt:notifyId];//封装回执消息
            [[SocketRocketUtility instance] sendData:receiptStr];// webSockt发送回执消息给服务器
            //            NSLog(@"收到了重复的消息");
            return;
        }else
        {
            NSString *receiptStr=[self getRecipt:notifyId];//封装回执消息
            //            NSLog(@"收到了第一条消息");
            [[SocketRocketUtility instance] sendData:receiptStr];// webSockt发送回执消息给服务器
        }
        
    }
    
    if(self.delegate&&[self.delegate respondsToSelector:@selector(receiveServerMessage:)]){
        [self.delegate receiveServerMessage:message];
    }
//    [self messageDisplay:receiveDic];
    //    [self otherSendTextMessageWithContent:message];
}

- (NSString*)getRecipt:(NSString*)notifyId
{
    NSDictionary *receipt=@{
                            @"request": @{
                                    @"version": @"1.0",
                                    @"msgType": @"receipt",
                                    @"sequenceNo": @(1513734318729)
                                    },
                            @"msgBody": @{
                                    @"notifyId": notifyId
                                    }
                            
                            };
    NSString *receiptStr=[receipt jsonString];
    return receiptStr;
}
- (BOOL)findNotifyId:(NSString*)notifyId InAry:(NSMutableArray*)notifyAry
{
    int  notifyIdCount=0;
    if ([notifyAry count]==1) {
        //        NSLog(@"数组只有一个元素");
        return NO;
    }
    for (int i=0;i<notifyAry.count;i++)
    {
        //        NSLog(@"遍历数组");
        NSDictionary *dic=[notifyAry objectAtIndex:i];
        if([[[dic allKeys] firstObject] isEqualToString:notifyId])
        {
            notifyIdCount++;
            //             return YES;
        }
        
    }
    if(notifyIdCount>1)
    {
        return YES;
    }
    return NO;
}

@end
